package com.jiangyao.common.handler;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.api.R;
import com.jiangyao.common.ApiResult;
import org.apache.catalina.connector.RequestFacade;
import org.apache.catalina.connector.ResponseFacade;
import org.apache.commons.lang.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.multipart.support.AbstractMultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;


/**
 * @author yych
 */
@Aspect
@Component
public class LogAdviceHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(LogAdviceHandler.class);

    /**
     * Pointcut 定义Pointcut，Pointcut的名称为aspectjMethod()，此方法没有返回值和参数
     * 该方法就是一个标识，不进行调用
     */
//    @Pointcut("execution(public * com.jiangyao.controller..*.*(..))")
    private void aspectjMethod() {
    }


    /**
     * Before 在核心业务执行前执行，不能阻止核心业务的调用。
     *
     * @param joinPoint
     */
//    @Before("aspectjMethod()")
    public void beforeAdvice(JoinPoint joinPoint) {
        try {
            // 用的最多 通知的签名
            Signature signature = joinPoint.getSignature();
            // 代理的是哪一个方法
            LOGGER.info("[interface][beforeAdvice]{}", signature);

            // 获取目标方法的参数信息
            Object[] objArr = joinPoint.getArgs();
            if (objArr != null && objArr.length > 0) {
                Map<String, String> parameterMap = new LinkedHashMap<>();

                for (Object obj : objArr) {
                    if (obj != null && !(obj instanceof RequestFacade) && !(obj instanceof ResponseFacade)) {
                        if (obj instanceof AbstractMultipartHttpServletRequest) {
                            break;
                        }

                        String param = obj.getClass().getName();
                        if (StringUtils.isNotBlank(param) && param.indexOf("com.jiangyao") != -1) {
                            LOGGER.info("[interface][beforeAdvice] param:{}", param);
                            String value = JSON.toJSONString(obj);
                            parameterMap.put(param, value);
                        }
                    } else {
                        // 获取RequestAttributes
                        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
                        // 从获取RequestAttributes中获取HttpServletRequest的信息
                        HttpServletRequest request = (HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);

                        Enumeration<String> enumeration = request.getParameterNames();
                        while (enumeration.hasMoreElements()) {
                            String parameter = enumeration.nextElement();
                            parameterMap.put(parameter, request.getParameter(parameter));
                        }
                    }
                }

                String str = JSON.toJSONString(parameterMap);
                LOGGER.info("[interface][beforeAdvice]{} 请求参数：{}", signature, str);
            }
        } catch (Exception e) {
            LOGGER.error("[interface][beforeAdvice Exception]", e);
        }

    }

    /**
     * AfterReturning 核心业务逻辑调用正常退出后，不管是否有返回值，正常退出后，均执行此Advice
     *
     * @param joinPoint
     */
//    @AfterReturning(value = "aspectjMethod()", returning = "retVal")
    public void afterReturningAdvice(JoinPoint joinPoint, ResponseEntity retVal) {
        try {
            // 用的最多 通知的签名
            Signature signature = joinPoint.getSignature();

            if (retVal != null) {
                if (retVal.getBody() instanceof R) {
                    ApiResult responseMsg = (ApiResult) retVal.getBody();
                    LOGGER.info("[interface][afterReturningAdvice]{} 响应结果:{}", signature, responseMsg);
                } else {
                    LOGGER.info("[interface][afterReturningAdvice]{} 响应结果:{}", signature, retVal.getBody());
                }
            }
        } catch (Exception e) {
            LOGGER.error("[interface][afterReturningAdvice Exception]", e);
        }
    }
}
